home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
wcl-21.lha
/
wcl-2.1
/
src
/
compiler
/
common
/
compile.lisp
< prev
next >
Wrap
Lisp/Scheme
|
1992-09-10
|
15KB
|
457 lines
;;; (C) Copyright 1990-1992 by Wade L. Hennessey. All rights reserved.
(defun comf (file &key
(output-file (merge-pathnames ".o" file))
(c-file (merge-pathnames ".c" file))
(verbose *compile-verbose*)
(print *compile-print*)
(config *config*)
(pic? *pic?*)
only-to-c?)
(initialize-compiler)
(let ((*package* *package*)
(*const-labels* (make-hash-table :test #'equal))
(*pic?* pic?)
(*config* config)
(*print-base* 10)
(*print-gensym* t)
(*input-stream-line-numbers?* (config-lisp-line-numbers? config))
(*new-function-info* (new-function-info-table 200))
(*referenced-c-info* nil)
(input-file (merge-pathnames file ".lisp"))
(code-file (tmp-file-name ".p"))
(k-file (tmp-file-name ".k"))
(package-file (tmp-file-name ".pkg"))
(win-file (tmp-file-name ".w")))
(unwind-protect
(progn
(with-open-file (input-stream input-file)
(with-open-file (*package-stream* package-file :direction :output)
(with-open-file (*c-stream* code-file :direction :output)
(with-open-file (*win-stream* win-file :direction :output)
(with-open-file (*k-stream* k-file :direction :output)
(let ((*compile-file-pathname* (pathname input-stream))
(*readtable* (if (config-lisp-line-numbers?
*config*)
*line-number-readtable*
*readtable*))
(*source-table*
(make-hash-table :size 300 :test #'equal))
(*external-procs*
(make-hash-table :size 300 :test #'eq)))
(when verbose
(format *standard-output* "~&Compiling file ~S~%"
*compile-file-pathname*))
(comf-begin)
(comf-loop input-stream print)
(comf-finish)))))))
(append-files c-file package-file win-file k-file code-file))
(del-files package-file win-file k-file code-file))
(if only-to-c?
(pathname c-file)
(progn (invoke-c-compiler (namestring c-file)
(namestring output-file))
(when verbose
(format *standard-output* "~&Wrote object file ~S~%"
output-file))
output-file))))
(defun comf-begin ()
(emit-configuration-info)
(emit-k "#include \"lisp.h\"~%~%"))
(defun comf-loop (input-stream print)
(loop for form = (progn
(clrhash *source-table*)
(read input-stream nil input-stream))
until (eq form input-stream)
;; HEY! make print option print something more meaningful
when print do (princ "Compiling top-level form")
for init = (comf-top-level-form form)
unless (null init)
append init into thunk-body
finally
(let ((init-name (file-init-thunk-name input-stream)))
(unless (null thunk-body)
(compile-define-function
(macroexpand-w `(defun ,init-name ()
,@thunk-body)))
(emit-win ":init ~S~%" init-name))
(maphash #'(lambda (lisp-name c-name)
(declare (ignore lisp-name))
(unless (eq c-name :done)
(emit-k "extern LP ~A();~%" c-name)))
*external-procs*))))
(defun comf-finish ()
(emit-k "~%~%")
(format *package-stream* ":end-package-info 0~%")
(emit-referenced-c-definitions)
(when (config-lisp-line-numbers? *config*)
(emit-k "#line 1 \"~A\"~%"
(namestring *compile-file-pathname*)))
(write-procedure-info *new-function-info* *win-stream*)
(emit-win ":end~%*/~%~%"))
(defun emit-configuration-info ()
(format *package-stream* "/*~%")
(format *package-stream* ":comment \"Compiled at ")
(print-time :stream *package-stream*)
(format *package-stream* "\"~%")
(format *package-stream* ":comment \"Compiler Configuration: ~A\"~%"
(config-name *config*))
(format *package-stream* ":comment \"Machine Configuration: ~A\"~%"
(machine-name *target-machine*))
(format *package-stream* ":comment \"cc command: ~A\"~%"
(basic-cc-string))
(format *package-stream* ":version ~A~%" 0))
(defun comf-top-level-form (form)
(if (atom form)
nil
(let ((mexp (macroexpand-w form))
(*current-line* (if (config-lisp-line-numbers? *config*)
(source-line form)
nil)))
(case (car mexp)
(define-function (compile-define-function mexp))
(define-variable (compile-define-var mexp))
(define-macro (compile-define-macro mexp))
(define-type (compile-define-type mexp))
(define-compiler-macro-1 (compile-define-compiler-macro-1 mexp))
(define-structure (compile-top-level-define-structure mexp))
(define-c-structure (compile-top-level-define-c-structure mexp))
(define-c-type-name (compile-top-level-define-c-type-name mexp))
(define-foreign-function
(compile-top-level-define-foreign-function mexp))
(define-setf (compile-top-level-define-setf mexp))
(proclaim (compile-top-level-proclaim mexp))
(progn (compile-top-level-progn mexp))
(eval-when (compile-top-level-eval-when mexp))
(in-package (compile-top-level-package-related-form mexp))
(add-winfo (compile-top-level-add-winfo mexp))
(t (list mexp))))))
(defun compile-top-level-add-winfo (form)
(emit-win (second form))
(emit-win "~%")
nil)
(defun compile-top-level-package-related-form (form)
(format *package-stream* ":package ~S ~%" form)
(eval form)
nil)
(defun compile-top-level-progn (form)
(loop for x in (cdr form)
for init = (comf-top-level-form x)
unless (null init)
append init into thunk-body
finally (return thunk-body)))
(defun compile-top-level-eval-when (form)
(destructuring-bind (ignore when . body) form
(declare (ignore ignore))
(when (member 'compile when)
(eval `(progn ,@body)))
(if (member 'load when)
(comf-top-level-form `(progn ,@body))
nil)))
(defun compile-top-level-define-c-type-name (form)
(destructuring-bind (define-c-type-name (q1 name) (q2 type)) form
(declare (ignore define-c-type-name q1 q2))
(emit-win ":c-type ~S ~S~%" name type)
(define-c-type-name name type)
nil))
(defun compile-top-level-define-foreign-function (form)
(eval form)
nil)
(defun compile-define-function (form)
(destructuring-bind (define-function (q1 name) kind
(q3 in-types) (q4 out-types)
(q5 body)
function-with-type-checks
function) form
(declare (ignore define-function q1 q2 q3 q4 q5))
(when (lookup-macro-expander name *macro-expanders* nil)
(remove-macro-expander name)
(warn "Redefining macro ~A as a function" name))
(let ((real-function
(if (and (eq kind :defmethod)
(config-full-type-checking? *config*))
function-with-type-checks
function)))
(let ((flabel (com-1 real-function)))
(unless (null flabel)
(add-proc-definition
name body function *compile-file-pathname*)
(when (eq kind :defmethod)
(proclaim-ftype-info name in-types out-types))
(emit-win ":sf ~S ~S~%" name flabel)))
nil)))
(defun compile-define-macro (form)
(eval form)
(destructuring-bind (define-macro
(q1 name)
(f1 function))
form
(declare (ignore define-macro q2 f1 q1))
(let ((flabel (com-1 `(named-macro-function ,name ,function))))
(emit-win ":sm ~S ~S~%" name flabel)
(list `(define-macro ',name #',name)))))
(defun compile-define-type (form)
(eval form)
(list form))
(defun compile-define-compiler-macro-1 (form)
(eval form)
(list form))
(defun compile-top-level-define-setf (form)
(eval form)
;; this sometimes breaks kcl
(list form))
(defun compile-top-level-define-structure (form)
(let ((info (second form))
(*print-structure* t))
(let ((*print-array* t))
(emit-win ":structure ~S ~S~%"
info
(lisp->c-proc-name (fluid-predicate-name info))))
(define-structure info)
(list form)))
(defun compile-top-level-define-c-structure (form)
(let ((info (second form))
(*print-structure* t)
(*print-array* t))
(emit-win ":c-type ~S ~S~%" (c-struct-info-name info) info)
(define-c-structure info)
nil))
(defun compile-define-var (form)
(destructuring-bind (i0 (i1 name) init-form doc-string type) form
(declare (ignore i0 i1 doc-string))
(ecase type
((:var :parameter) (proclaim-special-variable name))
(:constant (proclaim-constant-variable name init-form)))
(if (simple-constant? init-form)
(progn (emit-win "~S ~S ~S~%"
(if (eq type :constant) :sc :sv) name init-form)
nil)
(list form))))
(defun simple-constant? (x)
;; HEY! add vector and quoted list support. Add general quoted object stuff.
;; Have to emit all subobjects of the constant (i.e symbols)
;; as well as the constant.
(or (stringp x) (numberp x)))
(defun com-1 (form)
(let* ((*proc-chain* nil)
(tree (analyze form)))
(if (null tree)
(warn "Not emitting c code for ~A" (form-name form))
(if (top-level-proc-p tree)
(let ((*emitting-proc?* nil))
(back-end tree))
(error "Only expect top-level-procs at top-level")))))
(defun back-end (tree)
(when (config-beta? *config*)
(beta tree nil))
(improve tree)
(emit-code tree))
(defun compile-top-level-proclaim (form)
(destructuring-bind (ignore-1 decl-spec) form
(declare (ignore ignore-1))
(proclaim-w (eval decl-spec))
(emit-win ":proclaim ~S~%" decl-spec)
nil))
(defun proclaim-w (decl-spec)
(let ((decl (car decl-spec))
(spec (cdr decl-spec)))
(case decl
(optimize (loop for (quality value) in spec
do (case quality
(speed (setf *config*
(ecase value
((0 1 2) *default-config*)
(3 *fastest-config*))))
(safety nil))))
(declaration (loop for decl in spec
do (pushnew decl *ok-foreign-declarations*)))
(special (loop for special in spec
do (proclaim-special-variable special)))
(inline (loop for name in spec do (proclaim-inline-function name)))
(notinline (loop for name in spec
do (proclaim-notinline-function name)))
(type (loop with type = (first spec)
for var in (rest spec) do
(proclaim-variable-type var type)))
;; Punt for now. Maybe add ANSI interp later.
(function (let ((function-names spec))
(when (listp (second function-names))
(warn "Ignoring obsolete Cltl1 style declaration: ~S"
decl-spec))))
(ftype (destructuring-bind ((function in-types out-type) . names)
spec
(declare (ignore function))
(let ((out-types (if (listp out-type) ; (values ...) ?
(cdr out-type)
(list out-type))))
(loop for name in names
do (proclaim-ftype-info name in-types out-types)))))
(t (if (member decl *standard-type-specifier-symbols*)
;; HEY! record type info
nil
(unless (member decl *ok-foreign-declarations*)
(error "Unknown declaration ~A" decl-spec)))))
t))
(defun get-variable-info (name)
(gethash name *variable-info*))
(defun get-or-create-variable-info (name)
(or (get-variable-info name)
(setf (gethash name *variable-info*)
(make-variable-info :name name))))
(defun proclaim-variable-type (variable type)
(setf (variable-info-type (get-or-create-variable-info variable))
type))
(defun special-var-p (var)
(lookup-special-decl var (lex-env-decls *env*)))
(defun compiler-warn (string &rest args)
(incf *analysis-errors*)
(when (= *analysis-errors* 1)
(format *error-output*
"~%The following errors were detecting in the ~A:~% "
(form-name (lex-env-outermost-form *env*))))
(format *error-output* "~8T~A~%" (apply #'format nil string args))
(when *break-on-compiler-warn?* (break))
nil)
(defun w-warn (string &rest args)
(apply #'format *error-output* string args)
nil)
(defun form-name (form)
(or (and (listp form)
(case (first form)
(named-function (format nil "function ~A" (second form)))
(define-variable (format nil "global variable~A" (second form)))))
(let ((*print-level* 3)
(*print-length* 3))
(format nil "Top Level Form ~A" form))))
(defun initialize-compiler ()
(initialize-function-info-table)
(setf (c-compiler-command *sun-cc*) ; set here for correct tmp dir
(format nil "cc -w -temp=~A " (tmpdir)))
(unless *compiler-initialized?*
(setf *target-machine* (default-target-machine))
(read-all-libraries-compiler-info)
;; Add primitive, compiler-macro, and compiler-method inits.
(initialize-function-methods)
(setf *compiler-initialized?* t)))
(defun default-target-machine ()
#.(let ((machine-type (processor+os->machine-type
(installation-parameter "PROCESSOR")
(installation-parameter "OPERATING_SYSTEM")))
(cc (installation-parameter "CC")))
(case machine-type
(:sun-4 (cond ((string-equal cc "gcc") *sparcstation-gcc*)
((string-equal cc "cc") *sparcstation-cc*)))
(:decstation *decstation*))))
(defun tmp-file-name (format-string &rest args)
(pathname (format nil "~A/~D-~D~A"
(tmpdir)
(getpid)
(incf *tmp-file-counter*)
(apply #'format nil format-string args))))
(defun del-files (&rest files)
(loop for f in files
when (probe-file f)
do (delete-file f)))
(defun del-derived-files (&rest files)
(loop for file in files
do (del-files file
(merge-pathnames ".o" file)
(merge-pathnames ".c" file))))
(defun append-files (dest &rest sources)
(shell (format nil "cat ~{ ~A ~} > ~A"
(mapcar #'namestring sources)
(namestring dest))))
(defun file-init-thunk-name (pathname)
(gentemp (format nil "~A_INIT" (string-upcase (pathname-name pathname)))))
#+NATIVE-WCL
(defun compile-file (&rest args)
(apply #'comf args))
#+NATIVE-WCL
(defun compile (name &optional definition)
(let* ((real-name (if (null name) (gentemp "ANONYMOUS") name))
(def (if (null definition)
(function-lambda-expression name)
(setf (get real-name :function-definition)
`(defun ,real-name ,@(cdr definition))))))
(compile-and-load-def def)
(if (null name)
(symbol-function real-name)
name)))
#+NATIVE-WCL
(defun compile-and-load-def (def)
(let ((tmp-file (tmp-file-name "compile.lisp")))
(unwind-protect
(progn (with-open-file (output tmp-file :direction :output)
(print def output))
(load (compile-file tmp-file :verbose nil)
:verbose nil))
;; Leave all files around for debugging purposes
;; (del-files (make-pathname :defaults tmp-file :type "o"))
nil)))
(defun find-root-directory ()
(let ((cl-lib-file (format nil "libcl.so.~A" *cl-version*)))
(dolist (dir (unix->lisp-path-list (getenv "LD_LIBRARY_PATH")))
(let ((dir-name (concatenate 'string (namestring dir) "/")))
(when (probe-file (merge-pathnames cl-lib-file dir-name))
(if (char= (aref dir-name 0) #\/)
(return (pathname
(concatenate
'string
(subseq dir-name
0
(position #\/ dir-name
:end (1- (length dir-name))
:from-end t))
"/")))
(warn "Need full pathname in LD_LIBRARY_PATH instead of ~S"
dir-name)))))))
(pushnew :compiler *features*)